Skip to content

Conversation

@so-rose
Copy link

@so-rose so-rose commented Dec 17, 2025

spdx seems the best tool for the job of "software licenses as a type", and so I wish to use it in my library code. The only blocker is that spdx is not no_std, which I would like my library to be capable of.

So, as one does, I browsed the source code to see how std spdx really was. To my delight, the answer seems to be "not very": Outside the optional detection feature, all uses of std are soundly covered either by core, or by alloc (only needed for Box, Vec, String).

Goals
This PR's goal is to perform the minimal amount of changes needed to realize a widely usable License type, without modifying any logic whatsoever.

The core part of spdx, including the text feature, should now work on any no_std platform that supports alloc. This includes wasm, for example.

Non-Goals

  • Support for all of spdx incl. features that really do need std: The detection feature, in particular, makes legitimate use of std (HashMap and LazyLock). While there are doubtless good ways of achieving the same algorithms in no_std, they would differ in perhaps surprising ways. For example, HashMap and BTreeMap have vastly different performance properties, and the no_std ways of doing a LazyLock have serious tradeoffs - it would be wrong to naively impose these tradeoffs "just to make it work".
  • Using "better" types ex. a small string optimization. Sometimes, the types that make no_std difficult are not the right tool for the job. This is not one of those times - spdx is already architecturally capable of no_std, and the "replacement types" are either identical, or effectively identical. For that reason, it doesn't make sense to suggest changes to types.
  • Minimizing, eliminating, or altering allocation usage. I do think this is a worthy aspiration for any library code, but it's also invasive - as well as besides the point. spdx already works, and the way that spdx already works relies legitimately on alloc. To insist on removing alloc before no_std works at all would be unfortunate.

Maintenance Burden
I would argue that the maintenance burden of this PR is low, since no actual logic was changed.

In the future, one will have to default to using core:: and alloc::, instead of std::. If one really needs something in std, a decision will have to be made as to whether to feature-gate it behind std, or whether to replace the std thing with an appropriate no_std dependency.

It is a certain kind of price to pay for the wider platform support of no_std. But I would propose that this might actually be an upside. Arguably, a library providing a single data-oriented type doesn't need something non-optional from std, by virtue of being a nice way of interacting with a bag of bits. Any std-dependent extras should probably be feature-gated anyway! If one agrees with that sentiment, then why not formalize the convention in a way that the compiler will yell about?

Misc Notes

  • The std feature is explicitly depended on by each feature that requires it, even though it's not strictly needed. This is to make it explicit what needs std and what doesn't. Furthermore, in the future, if a feature is implemented for no_std, then that intention will be very obvious.
  • The test suite seems to pass with all ways of configuring the features.
  • Just for awareness, rust_analyzer doesn't always seem to catch no_std only problems when configured to enable all features by default. Some LSP configuration might be a good idea.
  • It might be a good idea to add some documentation. I didn't do that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant